home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
pgp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
28KB
|
1,213 lines
/*
* Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!
*
* Legal for distribution in the U.S./Canada ONLY! Exporting this file
* outside of the U.S./Canada may be in violation of ITAR regulations!
*/
/*
* This file contains all of the PGP routines necessary to sign, encrypt,
* verify and decrypt PGP messages in either the new PGP/MIME format, or
* in the older Application/Pgp format. It also contains some code to
* cache the user's passphrase for repeat use when decrypting or signing
* a message.
*/
#include "mutt.h"
#include "mutt_curses.h"
#include "send.h"
#include "pgp.h"
#include "mime.h"
#include "state.h"
#include "parse.h"
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#ifdef _PGPPATH
char PgpPass[STRING];
static time_t PgpExptime = 0; /* when does the cached passphrase expire? */
void pgp_void_passphrase (void)
{
memset (PgpPass, 0, sizeof (PgpPass));
PgpExptime = 0;
}
int pgp_valid_passphrase (void)
{
time_t now = time (NULL);
if (now < PgpExptime) return 1; /* just use the cached copy. */
pgp_void_passphrase ();
if (mutt_get_password ("Enter PGP passphrase:", PgpPass, sizeof (PgpPass)) == 0)
{
PgpExptime = time (NULL) + PgpTimeout;
return (1);
}
else
{
PgpExptime = 0;
return (0);
}
/* not reached */
}
void mutt_forget_passphrase (void)
{
pgp_void_passphrase ();
mutt_message ("PGP passphrase forgotten.");
}
static struct {
enum pgp_version v;
char *s;
} pgp_vstrings[] = {
{ PGP2, "pgp2" },
{ PGP3, "pgp3" },
{ PGP3, "pgp5" },
{ PGP_G10, "g10" },
{ PGP_UNKNOWN, NULL}
};
enum pgp_version pgp_version(void)
{
int i;
for(i = 0; pgp_vstrings[i].s; i++)
{
if(!strcasecmp(pgp_vstrings[i].s, PgpVersion))
return pgp_vstrings[i].v;
}
return PGP_UNKNOWN;
}
char *pgp_keyid(KEYINFO *k)
{
if(option(OPTPGPLONGIDS))
return k->keyid;
else
return (k->keyid + 8);
}
/* ----------------------------------------------------------------------------
* Routines for handing PGP input.
*/
/* print the current time to avoid spoofing of the signature output */
static void pgp_current_time (STATE *s)
{
time_t t;
char p[STRING];
state_puts ("[-- PGP output follows (current time: ", s);
t = time (NULL);
strfcpy (p, asctime (localtime (&t)), sizeof (p));
p[strlen (p) - 1] = 0; /* kill the newline */
state_puts (p, s);
state_puts (") --]\n", s);
}
/* Support for the Application/PGP Content Type. */
void application_pgp_handler (BODY *m, STATE *s)
{
int needpass = -1, pgp_keyblock = 0;
int clearsign = 0;
long start_pos = 0;
long bytes, last_pos, offset;
char buf[HUGE_STRING];
char outfile[_POSIX_PATH_MAX];
char tmpfname[_POSIX_PATH_MAX];
FILE *pgpout = NULL, *pgpin, *pgperr;
FILE *tmpfp;
pid_t thepid;
fseek (s->fpin, m->offset, 0);
last_pos = m->offset;
for (bytes = m->length; bytes > 0;)
{
if (fgets (buf, sizeof (buf) - 1, s->fpin) == NULL)
break;
offset = ftell (s->fpin);
bytes -= (offset - last_pos); /* don't rely on strlen(buf) */
last_pos = offset;
if (strncmp ("-----BEGIN PGP ", buf, 15) == 0)
{
clearsign = 0;
start_pos = last_pos;
if (strcmp ("MESSAGE-----\n", buf + 15) == 0)
needpass = 1;
else if (strcmp ("SIGNED MESSAGE-----\n", buf + 15) == 0)
{
clearsign = 1;
needpass = 0;
}
else if (!option(OPTDONTHANDLEPGPKEYS) &&
strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15) == 0)
{
needpass = 0;
pgp_keyblock =1;
}
else
{
if (s->prefix)
state_puts (s->prefix, s);
state_puts (buf, s);
continue;
}
if(!clearsign || s->flags & M_VERIFY)
{
/* invoke PGP */
mutt_mktemp (outfile);
if ((pgpout = safe_fopen (outfile, "w+")) == NULL)
{
mutt_perror (outfile);
return;
}
mutt_mktemp (tmpfname);
if ((tmpfp = safe_fopen(tmpfname, "w+")) == NULL)
{
mutt_perror(tmpfname);
fclose(pgpout); pgpout = NULL;
return;
}
fputs (buf, tmpfp);
while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL)
{
offset = ftell (s->fpin);
bytes -= (offset - last_pos); /* don't rely on strlen(buf) */
last_pos = offset;
fputs (buf, tmpfp);
if ((needpass && strcmp ("-----END PGP MESSAGE-----\n", buf) == 0) ||
(!needpass
&& (strcmp ("-----END PGP SIGNATURE-----\n", buf) == 0
|| strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",buf) == 0)))
break;
}
fclose(tmpfp);
if ((thepid = pgp_invoke_decode (&pgpin, NULL, &pgperr, -1,
fileno (pgpout), -1, tmpfname, needpass)) == -1)
{
fclose (pgpout); pgpout = NULL;
mutt_unlink(tmpfname);
state_puts ("[-- Error: unable to create PGP subprocess --]\n", s);
state_puts (buf, s);
continue;
}
if (needpass)
{
if (!pgp_valid_passphrase ())
pgp_void_passphrase ();
fputs (PgpPass, pgpin);
fputc ('\n', pgpin);
}
fclose (pgpin);
if (s->flags & M_DISPLAY)
pgp_current_time (s);
mutt_wait_filter (thepid);
mutt_unlink(tmpfname);
if (s->flags & M_DISPLAY)
mutt_copy_stream(pgperr, s->fpout);
fclose (pgperr);
if (s->flags & M_DISPLAY)
state_puts ("\n[-- End of PGP output --]\n\n", s);
}
if(s->flags & M_DISPLAY)
{
if (needpass)
state_puts ("[-- BEGIN PGP MESSAGE --]\n\n", s);
else if (pgp_keyblock)
state_puts ("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n", s);
else
state_puts ("[-- BEGIN PGP SIGNED MESSAGE --]\n\n", s);
}
/* Use PGP's output if there was no clearsig signature. */
if(!clearsign)
{
fflush (pgpout);
rewind (pgpout);
while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL)
{
if (s->prefix)
state_puts (s->prefix, s);
state_puts (buf, s);
}
}
/* Close the temporary files iff they were created.
* The condition used to be !clearsign || s->flags & M_VERIFY,
* but gcc would complain then.
*/
if(pgpout)
{
fclose (pgpout);
pgpout = NULL;
mutt_unlink(outfile);
}
/* decode clearsign stuff */
if(clearsign)
{
/* rationale: We want PGP's error messages, but in the times
* of PGP 5.0 we can't rely on PGP to do the dash
* escape decoding - so we have to do this
* ourselves.
*/
int armor_header = 1;
int complete = 1;
fseek(s->fpin, start_pos, SEEK_SET);
bytes += (last_pos - start_pos);
last_pos = start_pos;
offset = start_pos;
while(bytes > 0 && fgets(buf, sizeof(buf) - 1, s->fpin) != NULL)
{
offset = ftell(s->fpin);
bytes -= (offset - last_pos);
last_pos = offset;
if(complete)
{
if (!strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
break;
if(armor_header)
{
if(*buf == '\n')
armor_header = 0;
}
else
{
if(s->prefix)
state_puts(s->prefix, s);
if(buf[0] == '-' && buf [1] == ' ')
state_puts(buf + 2, s);
else
state_puts(buf, s);
}
}
else
{
if(!armor_header)
state_puts(buf, s);
}
complete = strchr(buf, '\n') != NULL;
}
if (complete && !strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
{
while(bytes > 0 && fgets(buf, sizeof(buf) - 1, s->fpin) != NULL